package main

import (
	"container/heap"
	"sync"
	"time"
)

type PlayerScore struct {
	PlayerID  string
	Score     int
	Timestamp int64 // 用于处理同分情况
}

type RankInfo struct {
	PlayerID string
	Rank     int
	Score    int
}

// 基于堆的排行榜实现
type Leaderboard struct {
	mu       sync.RWMutex
	scores   []*PlayerScore
	indexMap map[string]int // 玩家ID到索引的映射
}

func NewLeaderboard() *Leaderboard {
	return &Leaderboard{
		scores:   make([]*PlayerScore, 0),
		indexMap: make(map[string]int),
	}
}

// 更新玩家分数
func (lb *Leaderboard) UpdateScore(playerID string, score int) {
	lb.mu.Lock()
	defer lb.mu.Unlock()

	if idx, exists := lb.indexMap[playerID]; exists {
		// 更新现有玩家分数
		lb.scores[idx].Score = score
		lb.scores[idx].Timestamp = time.Now().UnixNano()
		heap.Fix(lb, idx)
	} else {
		// 添加新玩家
		ps := &PlayerScore{
			PlayerID:  playerID,
			Score:     score,
			Timestamp: time.Now().UnixNano(),
		}
		heap.Push(lb, ps)
	}
}

// 获取玩家排名
func (lb *Leaderboard) GetPlayerRank(playerID string) (RankInfo, bool) {
	lb.mu.RLock()
	defer lb.mu.RUnlock()

	idx, exists := lb.indexMap[playerID]
	if !exists {
		return RankInfo{}, false
	}

	// 计算密集排名
	rank := 1
	for i := 0; i < idx; i++ {
		if lb.scores[i].Score > lb.scores[idx].Score {
			rank++
		}
	}

	return RankInfo{
		PlayerID: playerID,
		Rank:     rank,
		Score:    lb.scores[idx].Score,
	}, true
}

// 获取前N名
func (lb *Leaderboard) GetTopN(n int) []RankInfo {
	lb.mu.RLock()
	defer lb.mu.RUnlock()

	if n > len(lb.scores) {
		n = len(lb.scores)
	}

	result := make([]RankInfo, n)
	currentRank := 1
	prevScore := -1

	for i := 0; i < n; i++ {
		if lb.scores[i].Score != prevScore {
			currentRank = i + 1
			prevScore = lb.scores[i].Score
		}
		result[i] = RankInfo{
			PlayerID: lb.scores[i].PlayerID,
			Rank:     currentRank,
			Score:    lb.scores[i].Score,
		}
	}
	return result
}

// 获取玩家周边排名
func (lb *Leaderboard) GetPlayerRankRange(playerID string, rangeSize int) []RankInfo {
	lb.mu.RLock()
	defer lb.mu.RUnlock()

	idx, exists := lb.indexMap[playerID]
	if !exists {
		return nil
	}

	start := max(0, idx-rangeSize)
	end := min(len(lb.scores)-1, idx+rangeSize)

	// 计算密集排名
	rankMap := make(map[int]int)
	currentRank := 1
	prevScore := -1

	for i := start; i <= end; i++ {
		if lb.scores[i].Score != prevScore {
			currentRank = i + 1
			prevScore = lb.scores[i].Score
		}
		rankMap[i] = currentRank
	}

	result := make([]RankInfo, end-start+1)
	for i := start; i <= end; i++ {
		result[i-start] = RankInfo{
			PlayerID: lb.scores[i].PlayerID,
			Rank:     rankMap[i],
			Score:    lb.scores[i].Score,
		}
	}
	return result
}

// 实现heap.Interface
func (lb *Leaderboard) Len() int { return len(lb.scores) }

func (lb *Leaderboard) Less(i, j int) bool {
	return lb.scores[i].Score > lb.scores[j].Score
}

func (lb *Leaderboard) Swap(i, j int) {
	lb.scores[i], lb.scores[j] = lb.scores[j], lb.scores[i]
	lb.indexMap[lb.scores[i].PlayerID] = i
	lb.indexMap[lb.scores[j].PlayerID] = j
}

func (lb *Leaderboard) Push(x interface{}) {
	ps := x.(*PlayerScore)
	lb.indexMap[ps.PlayerID] = len(lb.scores)
	lb.scores = append(lb.scores, ps)
}

func (lb *Leaderboard) Pop() interface{} {
	old := lb.scores
	n := len(old)
	ps := old[n-1]
	lb.scores = old[0 : n-1]
	delete(lb.indexMap, ps.PlayerID)
	return ps
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
